home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
minix
/
up1510b.tgz
/
up1510b
/
src
/
kernel
/
clock.c
next >
Wrap
C/C++ Source or Header
|
1990-07-23
|
14KB
|
393 lines
/* This file contains the code and data for the clock task. The clock task
* has a single entry point, clock_task(). It accepts four message types:
*
* HARD_INT: a clock interrupt has occurred
* GET_TIME: a process wants the real time
* SET_TIME: a process wants to set the real time
* SET_ALARM: a process wants to be alerted after a specified interval
*
* The input message is format m6. The parameters are as follows:
*
* m_type CLOCK_PROC FUNC NEW_TIME
* ---------------------------------------------
* | SET_ALARM | proc_nr |f to call| delta |
* |------------+----------+---------+---------|
* | HARD_INT | | | |
* |------------+----------+---------+---------|
* | GET_TIME | | | |
* |------------+----------+---------+---------|
* | SET_TIME | | | newtime |
* ---------------------------------------------
*
* When an alarm goes off, if the caller is a user process, a SIGALRM signal
* is sent to it. If it is a task, a function specified by the caller will
* be invoked. This function may, for example, send a message, but only if
* it is certain that the task will be blocked when the timer goes off.
*/
#include "kernel.h"
#include <signal.h>
#include <minix/callnr.h>
#include <minix/com.h>
#include "proc.h"
/* Constant definitions. */
#define MILLISEC 100 /* how often to call the scheduler (msec) */
#define SCHED_RATE (MILLISEC*HZ/1000) /* number of ticks per schedule */
/* Clock parameters. */
#if (CHIP == INTEL)
#define COUNTER_FREQ (2*TIMER_FREQ) /* counter frequency using sqare wave*/
#define LATCH_COUNT 0x00 /* cc00xxxx, c = channel, x = any */
#define SQUARE_WAVE 0x36 /* ccaammmb, a = access, m = mode, b = BCD */
/* 11x11, 11 = LSB then MSB, x11 = sq wave */
#define TIMER_COUNT ((unsigned) (TIMER_FREQ/HZ)) /* initial value for counter*/
#define TIMER_FREQ 1193182L /* clock frequency for timer in PC and AT */
#endif
#if (CHIP == M68000)
#define FLUSH_MASK 0x07 /* bit mask used for flushing RS232 input */
#define TIMER_FREQ 2457600L /* timer 3 input clock frequency */
#endif
/* Clock task variables. */
PRIVATE time_t boot_time; /* time in seconds of system boot */
PRIVATE time_t next_alarm; /* probable time of next alarm */
PRIVATE time_t pending_ticks; /* ticks seen by low level only */
PRIVATE time_t realtime; /* real time clock */
PRIVATE int sched_ticks = SCHED_RATE; /* counter: when 0, call scheduler */
PRIVATE struct proc *prev_ptr; /* last user process run by clock task */
PRIVATE message mc; /* message buffer for both input and output */
PRIVATE void (*watch_dog[NR_TASKS+1])(); /* watch_dog functions to call */
FORWARD void do_clocktick();
FORWARD void do_get_time();
FORWARD void do_set_time();
FORWARD void do_setalarm();
FORWARD void init_clock();
/*===========================================================================*
* clock_task *
*===========================================================================*/
PUBLIC void clock_task()
{
/* Main program of clock task. It determines which of the 4 possible
* calls this is by looking at 'mc.m_type'. Then it dispatches.
*/
int opcode;
init_clock(); /* initialize clock task */
/* Main loop of the clock task. Get work, process it, sometimes reply. */
while (TRUE) {
receive(ANY, &mc); /* go get a message */
opcode = mc.m_type; /* extract the function code */
lock();
realtime += pending_ticks; /* transfer ticks from low level handler */
pending_ticks = 0;
unlock();
switch (opcode) {
case SET_ALARM: do_setalarm(&mc); break;
case GET_TIME: do_get_time(); break;
case SET_TIME: do_set_time(&mc); break;
case HARD_INT: do_clocktick(); break;
default: panic("clock task got bad message", mc.m_type);
}
/* Send reply, except for clock tick. */
mc.m_type = OK;
if (opcode != HARD_INT) send(mc.m_source, &mc);
}
}
/*===========================================================================*
* do_setalarm *
*===========================================================================*/
PRIVATE void do_setalarm(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* A process wants an alarm signal or a task wants a given watch_dog function
* called after a specified interval. Record the request and check to see
* it is the very next alarm needed.
*/
register struct proc *rp;
int proc_nr; /* which process wants the alarm */
long delta_ticks; /* in how many clock ticks does he want it? */
void (*function)(); /* function to call (tasks only) */
/* Extract the parameters from the message. */
proc_nr = m_ptr->CLOCK_PROC_NR; /* process to interrupt later */
delta_ticks = m_ptr->DELTA_TICKS; /* how many ticks to wait */
function = m_ptr->FUNC_TO_CALL; /* function to call (tasks only) */
rp = proc_addr(proc_nr);
mc.SECONDS_LEFT = (rp->p_alarm == 0L ? 0 : (rp->p_alarm - realtime)/HZ );
rp->p_alarm = (delta_ticks == 0L ? 0L : realtime + delta_ticks);
if (istaskp(rp)) watch_dog[-proc_nr] = function;
/* Which alarm is next? */
next_alarm = MAX_P_LONG;
for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++)
if(rp->p_alarm != 0 && rp->p_alarm < next_alarm)next_alarm=rp->p_alarm;
}
/*===========================================================================*
* do_get_time *
*===========================================================================*/
PRIVATE void do_get_time()
{
/* Get and return the current clock time in ticks. */
mc.m_type = REAL_TIME; /* set message type for reply */
mc.NEW_TIME = boot_time + realtime/HZ; /* current real time */
}
/*===========================================================================*
* do_set_time *
*===========================================================================*/
PRIVATE void do_set_time(m_ptr)
message *m_ptr; /* pointer to request message */
{
/* Set the real time clock. Only the superuser can use this call. */
boot_time = m_ptr->NEW_TIME - realtime/HZ;
}
/*===========================================================================*
* do_clocktick *
*===========================================================================*/
PRIVATE void do_clocktick()
{
/* This routine called on clock ticks when a lot of work needs to be done. */
register struct proc *rp;
register int proc_nr;
if (next_alarm <= realtime) {
/* An alarm may have gone off, but proc may have exited, so check. */
next_alarm = MAX_P_LONG; /* start computing next alarm */
for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
if (rp->p_alarm != (time_t) 0) {
/* See if this alarm time has been reached. */
if (rp->p_alarm <= realtime) {
/* A timer has gone off. If it is a user proc,
* send it a signal. If it is a task, call the
* function previously specified by the task.
*/
if ( (proc_nr = proc_number(rp)) >= 0)
cause_sig(proc_nr, SIGALRM);
else
(*watch_dog[-proc_nr])();
rp->p_alarm = 0;
}
/* Work on determining which alarm is next. */
if (rp->p_alarm != (time_t)0 && rp->p_alarm < next_alarm)
next_alarm = rp->p_alarm;
}
}
}
/* If a user process has been running too long, pick another one. */
if (--sched_ticks == 0) {
if (bill_ptr == prev_ptr) lock_sched(); /* process has run too long */
sched_ticks = SCHED_RATE; /* reset quantum */
prev_ptr = bill_ptr; /* new previous process */
}
#if (CHIP == M68000)
if (rdy_head[SHADOW_Q]) unshadow(rdy_head[SHADOW_Q]);
#endif
}
#if (CHIP == INTEL)
/*===========================================================================*
* init_clock *
*===========================================================================*/
PRIVATE void init_clock()
{
/* Initialize channel 0 of the 8253A timer to e.g. 60 Hz. */
out_byte(TIMER_MODE, SQUARE_WAVE); /* set timer to run continuously */
out_byte(TIMER0, TIMER_COUNT); /* load timer low byte */
out_byte(TIMER0, TIMER_COUNT >> 8); /* load timer high byte */
enable_irq(CLOCK_IRQ); /* ready for clock interrupts */
}